package core;

import interfaces.Core_Events;
import gui.*;
import java.util.StringTokenizer;
import net.UDP_Core;
/**
 *
 * @author Groš
 */

/** main class for the application, this is a driver which says what to do */
public class Core  implements Core_Events {
    
    /** the length of sliding window, the buffer */
    public static final int WINDOW_LENGTH = 4;
    
    /** datagram length (in bytes) */
    public static final int DATAGRAM_LENGTH = 128;
    
    /** after <code>RETRANSMIT_COUNTER</code> failed tryes is connection evaluated as collapsed */
    public static final int RETRANSMIT_COUNTER = 5;
    
    /** how long the socket is blocked to receive packet */
    public static final int SOCKET_TIMEOUT = 200; // in miliseconds
    
    /** default local port for client */
    public static final int CLIENT_LOCAL_PORT = 5004;
    
    /** default local port for server */
    public static final int SERVER_LOCAL_PORT = 5005;
    
    /** default IP */
    public static final String DEFAULT_IP = "127.0.0.1";
    
    /** this path is used for storing files received by server */
    public static final String DOWNLOADS_DIRECTORY = 
            System.getProperty("user.dir") + java.io.File.separator + "downloads" + java.io.File.separator;
            
    
    private FileWindow fw;
    private ClientWindow cw;
    private ServerWindow sw;
    private StartWindow stw;
    private ErrorWindow ew;
    private UDP_Core udp;
    private String filePath;
    
    /** Contructor - open Start window and hide Error window */
    public Core(){
        gui_open_StartWindow();
        gui_hide_ErrorWindow();
    }
   
    /** receive messages from other parts of program (windows, logic,...) and process them
     * @param event message what is processed
     */
    public void core_message(String event) {
        if (event.equals("StW:OK")) gui_selectWindow();
        if (event.equals("FW:Open-File")) core_client_loadFile();
        if (event.equals("CW:Open-FCW")) gui_open_FileWindow();
        if (event.equals("CW:Send")) core_client_send();
        if (event.equals("CW:Stop")) core_client_stop();
        if (event.equals("SW:Start")) core_server_listen();
        if (event.equals("SW:Stop")) core_server_stop();
        if (event.startsWith("UDP:C>")) 
            gui_appendToClientWindow(core_parse(event, ">", 2));
        if (event.startsWith("UDP:CD>")) 
            gui_client_changeStateLine(core_parse(event, ">", 2));
        if (event.startsWith("UDP:S>")) 
            gui_appendToServerWindow(core_parse(event, ">", 2));
        if (event.startsWith("UDP:SD>")) 
            gui_server_changeStateLine(core_parse(event, ">", 2));
        if (event.startsWith("UDP:E>")) 
            gui_appendToErrorWindow(core_parse(event, ">", 2));
    }
    
    /** parse String to parts
     * @param text what is parsed
     * @param separator which separator is used
     * @param position which position is used to return
     * @return parsed part of String
     */
    public static String core_parse (String text, String separator, int position) {
        StringTokenizer st = new StringTokenizer(text, separator);
        String tokenized = null;
        for (int i=0; i<position; i++)
            tokenized = st.nextToken();
        return tokenized;
    }
    
    /** check if <code>DOWNLOADS_DIRECTORY</code> exists or not. if it doesnt this method creates it 
     *  @see core.Core#DOWNLOADS_DIRECTORY
     */
    private void core_makeDirectoryForIncomes(){
       java.io.File ddirectory = new java.io.File (DOWNLOADS_DIRECTORY);
       if (!ddirectory.exists())
           ddirectory.mkdir();
    }
    
    /** creates <code>UDP_Core</code> object
     * @see net.UDP_Core
     */
    private void core_makeUDP(){
        if (udp == null) 
            udp = new UDP_Core(this);
    }
    
    /** initiates server listening */
    private void core_server_listen(){
        core_makeUDP();
        
        int port;
        String ip;
        
        // check values from GUI
        try {
           port = Integer.parseInt(sw.getPort());
           ip = sw.getIP();
           if (ip == null || ip.equals("") || port < 1) { 
               cw.writeText("Field(s) for port and IP are not correctly filled"); 
               return;
           }
           
           // initiates server listening
           udp.set_server_listen(ip,port);
           
           // change buttons visibility
           sw.show_StartButton(false);
           sw.show_StopButton(true);
        }
        catch(NumberFormatException nfex) { sw.writeText("Port number is not correct");}
        catch(NullPointerException npex) {sw.writeText("Field(s) for port and IP are not filled");}
    }
    
    /** stop server listening */
    private void core_server_stop(){
        core_makeUDP();
        
        udp.set_server_stop();
        
        // change buttons visibility
        sw.show_StartButton(true);
        sw.show_StopButton(false);
    }
    
    /** initiates sending a file */
    private void core_client_send(){
        core_makeUDP();
        int port;
        String ip;
        
        // check values from GUI
       try {
           port = Integer.parseInt(cw.getPort());
           ip = cw.getIP();
           if (ip == null || ip.equals("") || port < 1) { 
               cw.writeText("Field(s) for port and IP are not correctly filled"); 
               return;
           }
           
           // change buttons visibility
           cw.show_ChooseFileButton(false);
           cw.show_SendButton(false);
           cw.show_StopButton(true);
           
           // initiates sending
           udp.set_client_send(ip, port, filePath);
       }
       catch(NumberFormatException nfex) { cw.writeText("Port number is not correct");}
       catch(NullPointerException npex) {cw.writeText("Field(s) for port and IP are not filled");}
    }
    
    /** client is stop - interrupted sending */
    private void core_client_stop() {
        core_makeUDP();
        
        udp.set_client_stop();
        
        // change buttons visibility
        cw.show_ChooseFileButton(true);
        cw.show_SendButton(true);
        cw.show_StopButton(false);
    }
    
    /** initiates to choose file to load */
    private void core_client_loadFile(){
        // get file path from FileChooser Window
        filePath = fw.getSelectedFile().getPath();
        fw.dispose();
        if (filePath != null) {
            // if OK set file path and change button visibility
            cw.show_filePath(filePath);
            cw.show_SendButton(true);
        }
    }
    
    /** change data in stateline - how many bytes is received
     * @param text only number of bytes which are received
     */
    private void gui_server_changeStateLine(String text) {
        sw.changeStateLine(text);
    }
    
    /** change data in stateline - how many bytes is sent
     * @param text only number of bytes which are received
     */
    private void gui_client_changeStateLine(String text) {
        cw.changeStateLine(text);
    }
    
    /** add text (on a new line) to clients window text area 
     *  @param text what to add
     */
    private void gui_appendToClientWindow(String text) {
        final String ftext = text;
        
        // add in a thread - safer
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                cw.writeText(ftext);
            }
        });
    }
    
    /** add text (on a new line) to server window text area 
     *  @param text what to add
     */
    private void gui_appendToServerWindow(String text) {
        final String ftext = text;
        
        // add in a thread - safer
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                sw.writeText(ftext);
            }
        });
    }
    
    /** add text (on a new line) to error window text area 
     *  @param text what to add
     */
    private void gui_appendToErrorWindow(String text) {
        final String ftext = text;
        
        // add in a thread - safer
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                ew.writeText(ftext);
            }
        });
    }
    
    /** maintain which windows opens - client or server */
    private void gui_selectWindow(){
        String selection = stw.getSelectedRB();
        if (selection.equals("client"))
            gui_open_ClientWindow();
        if (selection.equals("server"))
            gui_open_ServerWindow();
        if (selection.equals("none"));
    }
    
    /** creates new FileChooser window */
    private void gui_open_FileWindow() {
        fw = new FileWindow(this);
    }
    
    /** creates new Client window */
    private void gui_open_ClientWindow() {
        cw = new ClientWindow(this);
        
        // change buttons visibility
        cw.show_ChooseFileButton(true);
        cw.show_SendButton(false);
        cw.show_StopButton(false);
    }
    
    /** close (=dispose) Client window */
    private void gui_close_ClientWindow() {};
    
    /** creates new Server window */
    private void gui_open_ServerWindow() {
        core_makeDirectoryForIncomes();
        sw = new ServerWindow(this);
        
        // change buttons visibility
        sw.show_StartButton(true);
        sw.show_StopButton(false);
    }
    
    /** close (= dispose) Server window */
    private void gui_close_ServerWindow() {};
    
    /** creates new Start window */
    private void gui_open_StartWindow() {
        stw = new StartWindow(this);
    }
    
    /** close (= dispose) Start window */
    private void gui_close_StartWindow() {};
    
    /** shows (= visibility is set to visible) Error window */
    private void gui_show_ErrorWindow() {
        ew.setWindowVisibility(false);
    }
    
    /** hides (= visibility is set to hide) Error window */
    private void gui_hide_ErrorWindow() {
        if (ew == null) ew = new ErrorWindow(this);
        ew.setWindowVisibility(false);
    };
    
    
}
